package jp.ac.hosei.gaedemo.controller;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import jp.ac.hosei.gaedemo.dto.SearchCondition;
import jp.ac.hosei.gaedemo.model.Schedule;
import jp.ac.hosei.gaedemo.service.SchedulerService;

import net.fortuna.ical4j.data.CalendarOutputter;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.TimeZoneRegistry;
import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
import net.fortuna.ical4j.model.ValidationException;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.component.VTimeZone;
import net.fortuna.ical4j.model.property.CalScale;
import net.fortuna.ical4j.model.property.Description;
import net.fortuna.ical4j.model.property.DtEnd;
import net.fortuna.ical4j.model.property.DtStart;
import net.fortuna.ical4j.model.property.LastModified;
import net.fortuna.ical4j.model.property.Location;
import net.fortuna.ical4j.model.property.ProdId;
import net.fortuna.ical4j.model.property.Summary;
import net.fortuna.ical4j.model.property.Uid;
import net.fortuna.ical4j.model.property.Version;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

public class PullController extends Controller {

    private SchedulerService service = new SchedulerService();
    @Override
    public Navigation run() throws Exception {
        // 検索の実行とRequestスコープの変数に格納
        String title = asString("title");
        Date fromDate = asDate("fromDate", "yyyy/MM/dd");
        Date toDate = asDate("toDate", "yyyy/MM/dd");

        SearchCondition sc = new SearchCondition();
        sc.setTitle(title);
        sc.setFromDate(fromDate);
        sc.setToDate(toDate);

        // 条件に合うスケジュールを取得
        List<Schedule> scheduleList = service.getScheduleByCond(sc);

        // 検索結果をiCalendar形式に変換する処理を書く
        String iCalSchedule = convertICalFormat(scheduleList);

        // コンテンツタイプの設定
        response.setContentType("text/calendar; charset=UTF-8");

        // データ要素をダウンロード(第一引数はダウンロードファイル名、第二引数はデータのByte配列)
        download("ical.ics", iCalSchedule.getBytes("UTF-8"));

        return null;
    }
    

    /**
     * スケジュールリストをiCalendar形式に変換する処理
     * @param scheduleList
     * @return 
     * @throws IOException
     * @throws ValidationException
     */
    private String convertICalFormat(List<Schedule> scheduleList) throws IOException, ValidationException {
        

        // カレンダの生成
        Calendar calendar = new Calendar();
        calendar.getProperties().add(new ProdId("gaedemo")); //icalを出力するアプリ識別子
        calendar.getProperties().add(CalScale.GREGORIAN);
        calendar.getProperties().add(Version.VERSION_2_0);

        // カレンダにイベントを追加(スケジュールのリスト分VEventを作成)
        for (Schedule schedule : scheduleList) {
            VEvent event = getEventFactory(schedule);
            calendar.getComponents().add(event);
        }

        // カレンダを文字列として書き出す
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        CalendarOutputter outputter = new CalendarOutputter();
        outputter.output(calendar, baos);
        String calendarAsString = baos.toString("UTF-8");
        
        return calendarAsString;
    }
    
    /**
     * 与えられたScheduleオブジェクトをVEventに変換し返却
     * @param schedule
     * @return
     * @throws IOException
     * @throws ValidationException
     */
    private VEvent getEventFactory(Schedule schedule) throws IOException, ValidationException {
        
        // イベントの生成
        VEvent event = new VEvent();
        // UID
        event.getProperties().add(new Uid(String.valueOf(schedule.getKey().getId())));
        // タイムゾーン
        TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance()
                .createRegistry();
        net.fortuna.ical4j.model.TimeZone timezoneAsIcalTimeZone = registry
                .getTimeZone("Asia/Tokyo"); //必要に応じてプロパティファイル等から取得
        VTimeZone tz = timezoneAsIcalTimeZone.getVTimeZone();
        event.getProperties().add(tz.getTimeZoneId());
        // サマリ（タイトル）
        event.getProperties().add(new Summary(schedule.getTitle()));
        // 詳細
        StringBuilder sb = new StringBuilder();
        sb.append("詳細：");
        sb.append(schedule.getComment());
        sb.append(System.getProperty("line.separator"));
        sb.append("添付ファイル：");
        String attachmentFileUrl = request.getScheme() + "://" + 
                request.getServerName() + ":" + 
                request.getServerPort() + "/show?keyName=" + schedule.getAttachmentKey();
        sb.append(attachmentFileUrl);
        sb.append(System.getProperty("line.separator"));
        sb.append("添付ファイルメモ：");
        sb.append(schedule.getContent());
        event.getProperties().add(new Description(sb.toString()));
        // 場所
        event.getProperties().add(new Location(schedule.getPlace()));
        // 最終更新日時
        event.getProperties().add(
                new LastModified(new DateTime(schedule.getCreateDate())));
        // 開始日時
        event.getProperties().add(
                new DtStart(new DateTime(schedule.getStartDate())));
        // 終了日時
        event.getProperties().add(
                new DtEnd(new DateTime(schedule.getEndDate())));
        
        return event;
    }
}
